package Presenter;

import Constraints.IConstraint;
import Core.ErrorMessage;
import Exceptions.ConstraintErrorException;
import Factory.IConstraintFactory;
import Factory.Impl.ConstraintFactory;
import Model.Core.Impl.ActorEntity;
import Model.Core.Impl.LinkEntity;
import Model.Core.Impl.MessageEntity;
import Model.Core.Impl.ObjectEntity;
import Model.Core.Tip.Tip;
import Model.Core.Tip.TipMoment;
import Model.Core.Tip.TipType;
import Model.Diagrams.CommunicationDiagram;
import Model.Diagrams.StateMachine;
import Model.Draw.Entities.ObjectDraw;
import Model.Draw.Events.ManifestEntityDoneListener;
import Model.Draw.Events.ManifestElementEvent;
import Model.Draw.Events.ManifestStateEvent;
import Model.Draw.Events.ShowTipEvent;
import Model.Draw.Events.ShowTipListener;
import Model.Draw.IDraw;
import Model.Draw.IEntityDraw;
import Model.Draw.Point;
import Services.IDrawService;
import Services.Impl.DrawService;
import ViewInterfaces.ICommunicationDiagramDrawView;
import java.util.List;

/**
 * Projeto de TCC: Editor de Diagramas de comunicação BlueJ
 * @author Jose Luz e Michele Puretachi
 */
public class CommunicationDiagramPresenter implements ManifestEntityDoneListener, ShowTipListener {

    private ICommunicationDiagramDrawView view;
    private IDrawService drawService;
    private IConstraintFactory constraintFactory;
    private CommunicationDiagram comunicationDiagram;

    public CommunicationDiagramPresenter(ICommunicationDiagramDrawView view) {
        this.view = view;
        drawService = new DrawService();
        drawService.registerShowTipsListener(this);
        constraintFactory = new ConstraintFactory();
        comunicationDiagram = new CommunicationDiagram();
    }

    public void linkEntitySelected() {
        LinkEntity link = new LinkEntity();
        link.addGraphicalManifestListener(this);
        drawService.setCurrentElement(link);
        drawService.configureContraint(constraintFactory.getLinkConstraint());
    }

    public void objectEntitySelected() {
        ObjectEntity object = new ObjectEntity();
        comunicationDiagram.checkNameEntity(object);
        object.addGraphicalManifestListener(this);
        drawService.setCurrentElement(object);
        drawService.configureContraint(constraintFactory.getObjectConstraint());
    }

    public void messageEntitySelected() {
        MessageEntity message = new MessageEntity();
        message.addGraphicalManifestListener(this);
        drawService.setCurrentElement(message);
        drawService.configureContraint(constraintFactory.getMessageConstraint());
    }

    public void actorEntitySelected() {
        ActorEntity actor = new ActorEntity();
        comunicationDiagram.checkNameEntity(actor);
        actor.addGraphicalManifestListener(this);
        drawService.setCurrentElement(actor);
        drawService.configureContraint(constraintFactory.getActorConstraint());
    }

    public void unselectAll() {
        view.unselectAllEntities();
    }

    public void newEntry(Point point) {
        List<IEntityDraw> draws = view.tryGetDrawAt(point);
        view.selectEntityFrom(point);
        view.updateCommunicationCanvas();
        if (draws.size() >= 1) {
            view.showMessage(draws.get(0).getEntity().findTipBy(TipType.Action, TipMoment.Selection).getMessage(), false);
        } else {
            view.cleanMessage();
        }
        try {
            drawService.newEntry(draws.size() >= 1 ? draws.get(0) : point);
        } catch (ConstraintErrorException ce) {
            view.showMessage(ce.getMessage(), true);
        } catch (Exception e) {
            view.showMessage(e.getMessage(), true);
        }
    }

    public void moveDraw(IDraw selectedDraw, Point clickedPoint) {
        view.moveDraw(selectedDraw, clickedPoint);
        view.enableMoving(false);
        view.cleanMessage();
        view.showRenameField(false);
        view.updateCommunicationCanvas();
    }

    @Override
    public void ShowTipHandler(ShowTipEvent event) {
        Tip tip = (Tip) event.getSource();
        view.showMessage(tip.getMessage(), tip.getType() == TipType.Error);
    }

    @Override
    public void manifestEntityDoneHandler(ManifestElementEvent e) {
        IEntityDraw draw = (IEntityDraw) e.getSource();
        view.manifestEntityDraw(draw);
        view.saveDraw(draw);

        //diagramView.showStateMachine(((ObjectEntity)draw.getEntity()).getStateMachine());
        comunicationDiagram.addEntity(draw.getEntity());
    }

    @Override
    public void manifestStateMachineDoneHandler(ManifestStateEvent e) {
        StateMachine stateMachine = (StateMachine) e.getSource();
        view.manifestStateMachine(stateMachine);
        view.updateCommunicationCanvas();
    }

    public void StartRenameEntity(IEntityDraw selectedDraw) {
        view.setRenameDraw(selectedDraw);
        view.showMessage(selectedDraw.getEntity().findTipBy(TipType.Action, TipMoment.Rename).getMessage(), false);
        view.showRenameField(true);
        view.updateCommunicationCanvas();
    }

    public void RenameEntity(IDraw draw, String name) {
        IConstraint constraint = constraintFactory.getCommunicationDiagramConstraint();
        List<ErrorMessage> errors = constraint.Validate(new Object[]{comunicationDiagram, draw, name});
        if (errors == null) {
            draw.rename(name);
            view.cleanMessage();
            view.showRenameField(false);
            if (draw instanceof ObjectDraw && ((ObjectDraw) draw).getEntity() != null) {
                ObjectEntity objectEntity = (ObjectEntity) ((ObjectDraw) draw).getEntity();
                view.updateTabWith(name, objectEntity.getStateMachine().getManifestArea());
            }
            view.updateCommunicationCanvas();
        } else {
            StringBuilder msgError = new StringBuilder();
            for (ErrorMessage error : errors) {
                msgError.append(error.getMessage());
            }
            view.showMessage(msgError.toString(), true);
        }
    }

    public void StartMoveEntity(IEntityDraw selectedDraw) {
        view.enableMoving(true);
        view.showMessage(selectedDraw.getEntity().findTipBy(TipType.Action, TipMoment.Move).getMessage(), false);
    }

    public void updateCanvas() {
        view.updateCommunicationCanvas();
    }

    public void configureContext() {
        view.configureCommunicationContext();
    }
}